home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpdfo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  32.3 KB  |  1,190 lines

  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpdfo.c,v 1.5 2000/09/19 19:00:17 lpd Exp $ */
  20. /* Cos object support */
  21. #include "memory_.h"
  22. #include "string_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gsparam.h"
  26. #include "gsutil.h"        /* for bytes_compare */
  27. #include "gdevpdfx.h"
  28. #include "gdevpdfo.h"
  29. #include "strimpl.h"
  30. #include "sa85x.h"
  31. #include "slzwx.h"
  32. #include "sstring.h"
  33. #include "szlibx.h"
  34.  
  35. #define CHECK(expr)\
  36.   BEGIN if ((code = (expr)) < 0) return code; END
  37.  
  38. /* ---------------- Structure definitions ---------------- */
  39.  
  40. /*
  41.  * Define the generic structure for elements of arrays and
  42.  * dictionaries/streams.
  43.  */
  44. #define cos_element_common(etype)\
  45.     etype *next
  46. struct cos_element_s {
  47.     cos_element_common(cos_element_t);
  48. };
  49. #define private_st_cos_element()    /* in gdevpdfo.c */\
  50.   gs_private_st_ptrs1(st_cos_element, cos_element_t, "cos_element_t",\
  51.     cos_element_enum_ptrs, cos_element_reloc_ptrs, next)
  52. #define cos_element_num_ptrs 1
  53.  
  54. /*
  55.  * Define the structure for a piece of stream contents.
  56.  */
  57. struct cos_stream_piece_s {
  58.     cos_element_common(cos_stream_piece_t);
  59.     long position;        /* in streams file */
  60.     uint size;
  61. };
  62. #define private_st_cos_stream_piece()    /* in gdevpdfo.c */\
  63.   gs_private_st_suffix_add0_local(st_cos_stream_piece, cos_stream_piece_t,\
  64.     "cos_stream_piece_t", cos_element_enum_ptrs, cos_element_reloc_ptrs,\
  65.     st_cos_element)
  66.  
  67. /*
  68.  * Define Cos arrays, dictionaries, and streams.
  69.  */
  70.      /* array */
  71. struct cos_array_element_s {
  72.     cos_element_common(cos_array_element_t);
  73.     long index;
  74.     cos_value_t value;
  75. };
  76. #define private_st_cos_array_element()    /* in gdevpdfo.c */\
  77.   gs_private_st_composite(st_cos_array_element, cos_array_element_t,\
  78.     "cos_array_element_t", cos_array_element_enum_ptrs, cos_array_element_reloc_ptrs)
  79.     /* dict */
  80. struct cos_dict_element_s {
  81.     cos_element_common(cos_dict_element_t);
  82.     gs_string key;
  83.     bool owns_key;    /* if false, key is shared, do not trace or free */
  84.     cos_value_t value;
  85. };
  86. #define private_st_cos_dict_element()    /* in gdevpdfo.c */\
  87.   gs_private_st_composite(st_cos_dict_element, cos_dict_element_t,\
  88.     "cos_dict_element_t", cos_dict_element_enum_ptrs, cos_dict_element_reloc_ptrs)
  89.  
  90. /* GC descriptors */
  91. private_st_cos_element();
  92. private_st_cos_stream_piece();
  93. private_st_cos_object();
  94. private_st_cos_value();
  95. private_st_cos_array_element();
  96. private_st_cos_dict_element();
  97.  
  98. /* GC procedures */
  99. private
  100. ENUM_PTRS_WITH(cos_value_enum_ptrs, cos_value_t *pcv) return 0;
  101.  case 0:
  102.     switch (pcv->value_type) {
  103.     case COS_VALUE_SCALAR:
  104.     return ENUM_STRING(&pcv->contents.chars);
  105.     case COS_VALUE_CONST:
  106.     break;
  107.     case COS_VALUE_OBJECT:
  108.     case COS_VALUE_RESOURCE:
  109.     return ENUM_OBJ(pcv->contents.object);
  110.     }
  111.     return 0;
  112. ENUM_PTRS_END
  113. private
  114. RELOC_PTRS_WITH(cos_value_reloc_ptrs, cos_value_t *pcv)
  115. {
  116.     switch (pcv->value_type) {
  117.     case COS_VALUE_SCALAR:
  118.     RELOC_STRING_VAR(pcv->contents.chars);
  119.     case COS_VALUE_CONST:
  120.     break;
  121.     case COS_VALUE_OBJECT:
  122.     case COS_VALUE_RESOURCE:
  123.     RELOC_VAR(pcv->contents.object);
  124.     break;
  125.     }
  126. }
  127. RELOC_PTRS_END
  128. private
  129. ENUM_PTRS_WITH(cos_array_element_enum_ptrs, cos_array_element_t *pcae)
  130. {
  131.     return (index < cos_element_num_ptrs ?
  132.         ENUM_USING_PREFIX(st_cos_element, 0) :
  133.         ENUM_USING(st_cos_value, &pcae->value, sizeof(cos_value_t),
  134.                index - cos_element_num_ptrs));
  135. }
  136. ENUM_PTRS_END
  137. private
  138. RELOC_PTRS_WITH(cos_array_element_reloc_ptrs, cos_array_element_t *pcae)
  139. {
  140.     RELOC_PREFIX(st_cos_element);
  141.     RELOC_USING(st_cos_value, &pcae->value, sizeof(cos_value_t));
  142. }
  143. RELOC_PTRS_END
  144. private
  145. ENUM_PTRS_WITH(cos_dict_element_enum_ptrs, cos_dict_element_t *pcde)
  146. {
  147.     return (index < cos_element_num_ptrs ?
  148.         ENUM_USING_PREFIX(st_cos_element, 0) :
  149.         (index -= cos_element_num_ptrs) > 0 ?
  150.         ENUM_USING(st_cos_value, &pcde->value, sizeof(cos_value_t),
  151.                index - 1) :
  152.         pcde->owns_key ? ENUM_STRING(&pcde->key) : ENUM_OBJ(NULL));
  153. }
  154. ENUM_PTRS_END
  155. private
  156. RELOC_PTRS_WITH(cos_dict_element_reloc_ptrs, cos_dict_element_t *pcde)
  157. {
  158.     RELOC_PREFIX(st_cos_element);
  159.     if (pcde->owns_key)
  160.     RELOC_STRING_VAR(pcde->key);
  161.     RELOC_USING(st_cos_value, &pcde->value, sizeof(cos_value_t));
  162. }
  163. RELOC_PTRS_END
  164.  
  165. /* ---------------- Generic support ---------------- */
  166.  
  167. /* Initialize a just-allocated cos object. */
  168. private void
  169. cos_object_init(cos_object_t *pco, gx_device_pdf *pdev,
  170.         const cos_object_procs_t *procs)
  171. {
  172.     if (pco) {
  173.     pco->cos_procs = procs;
  174.     pco->id = 0;
  175.     pco->elements = 0;
  176.     pco->pieces = 0;
  177.     pco->pdev = pdev;
  178.     pco->is_open = true;
  179.     pco->is_graphics = false;
  180.     pco->written = false;
  181.     }
  182. }
  183.  
  184. /* Get the allocator for a Cos object. */
  185. gs_memory_t *
  186. cos_object_memory(const cos_object_t *pco)
  187. {
  188.     return pco->pdev->pdf_memory;
  189. }
  190.  
  191. /* Change a generic cos object into one of a specific type. */
  192. int
  193. cos_become(cos_object_t *pco, cos_type_t cotype)
  194. {
  195.     if (cos_type(pco) != cos_type_generic)
  196.     return_error(gs_error_typecheck);
  197.     cos_type(pco) = cotype;
  198.     return 0;
  199. }
  200.  
  201. /* Release a cos object. */
  202. cos_proc_release(cos_release);    /* check prototype */
  203. void
  204. cos_release(cos_object_t *pco, client_name_t cname)
  205. {
  206.     pco->cos_procs->release(pco, cname);
  207. }
  208.  
  209. /* Free a cos object. */
  210. void
  211. cos_free(cos_object_t *pco, client_name_t cname)
  212. {
  213.     cos_release(pco, cname);
  214.     gs_free_object(cos_object_memory(pco), pco, cname);
  215. }
  216.  
  217. /* Write a cos object on the output. */
  218. cos_proc_write(cos_write);    /* check prototype */
  219. int
  220. cos_write(const cos_object_t *pco, gx_device_pdf *pdev)
  221. {
  222.     return pco->cos_procs->write(pco, pdev);
  223. }
  224.  
  225. /* Write a cos object as a PDF object. */
  226. int
  227. cos_write_object(cos_object_t *pco, gx_device_pdf *pdev)
  228. {
  229.     int code;
  230.  
  231.     if (pco->id == 0 || pco->written)
  232.     return_error(gs_error_Fatal);
  233.     pdf_open_separate(pdev, pco->id);
  234.     code = cos_write(pco, pdev);
  235.     pdf_end_separate(pdev);
  236.     pco->written = true;
  237.     return code;
  238. }
  239.  
  240. /* Make a value to store into a composite object. */
  241. const cos_value_t *
  242. cos_string_value(cos_value_t *pcv, const byte *data, uint size)
  243. {
  244.     /*
  245.      * It's OK to break const here, because the value will be copied
  246.      * before being stored in the collection.
  247.      */
  248.     pcv->contents.chars.data = (byte *)data;
  249.     pcv->contents.chars.size = size;
  250.     pcv->value_type = COS_VALUE_SCALAR;
  251.     return pcv;
  252. }
  253. const cos_value_t *
  254. cos_c_string_value(cos_value_t *pcv, const char *str)
  255. {
  256.     /*
  257.      * We shouldn't break const here, because the value will not be copied
  258.      * or freed (or traced), but that would require a lot of bothersome
  259.      * casting elsewhere.
  260.      */
  261.     pcv->contents.chars.data = (byte *)str;
  262.     pcv->contents.chars.size = strlen(str);
  263.     pcv->value_type = COS_VALUE_CONST;
  264.     return pcv;
  265. }
  266. const cos_value_t *
  267. cos_object_value(cos_value_t *pcv, cos_object_t *pco)
  268. {
  269.     pcv->contents.object = pco;
  270.     pcv->value_type = COS_VALUE_OBJECT;
  271.     return pcv;
  272. }
  273. const cos_value_t *
  274. cos_resource_value(cos_value_t *pcv, cos_object_t *pco)
  275. {
  276.     pcv->contents.object = pco;
  277.     pcv->value_type = COS_VALUE_RESOURCE;
  278.     return pcv;
  279. }
  280.  
  281. /* Free a value. */
  282. void
  283. cos_value_free(const cos_value_t *pcv, const cos_object_t *pco,
  284.            client_name_t cname)
  285. {
  286.     switch (pcv->value_type) {
  287.     case COS_VALUE_SCALAR:
  288.     gs_free_string(cos_object_memory(pco), pcv->contents.chars.data,
  289.                pcv->contents.chars.size, cname);
  290.     case COS_VALUE_CONST:
  291.     break;
  292.     case COS_VALUE_OBJECT:
  293.     /* Free the object if this is the only reference to it. */
  294.     if (!pcv->contents.object->id)
  295.         cos_free(pcv->contents.object, cname);
  296.     case COS_VALUE_RESOURCE:
  297.     break;
  298.     }
  299. }
  300.  
  301. /* Write a value on the output. */
  302. int
  303. cos_value_write(const cos_value_t *pcv, gx_device_pdf *pdev)
  304. {
  305.     switch (pcv->value_type) {
  306.     case COS_VALUE_SCALAR:
  307.     case COS_VALUE_CONST:
  308.     pdf_write_value(pdev, pcv->contents.chars.data,
  309.             pcv->contents.chars.size);
  310.     break;
  311.     case COS_VALUE_RESOURCE:
  312.     pprintld1(pdev->strm, "/R%ld", pcv->contents.object->id);
  313.     break;
  314.     case COS_VALUE_OBJECT: {
  315.     cos_object_t *pco = pcv->contents.object;
  316.  
  317.     if (!pco->id)
  318.         return cos_write(pco, pdev);
  319.     pprintld1(pdev->strm, "%ld 0 R", pco->id);
  320.     break;
  321.     }
  322.     default:            /* can't happen */
  323.     return_error(gs_error_Fatal);
  324.     }
  325.     return 0;
  326. }
  327.  
  328. /* Copy a value if necessary for putting into an array or dictionary. */
  329. private int
  330. cos_copy_element_value(cos_value_t *pcv, gs_memory_t *mem,
  331.                const cos_value_t *pvalue, bool copy)
  332. {
  333.     *pcv = *pvalue;
  334.     if (pvalue->value_type == COS_VALUE_SCALAR && copy) {
  335.     byte *value_data = gs_alloc_string(mem, pvalue->contents.chars.size,
  336.                        "cos_copy_element_value");
  337.  
  338.     if (value_data == 0)
  339.         return_error(gs_error_VMerror);
  340.     memcpy(value_data, pvalue->contents.chars.data,
  341.            pvalue->contents.chars.size);
  342.     pcv->contents.chars.data = value_data;
  343.     }
  344.     return 0;
  345. }
  346.  
  347. /* Release a value copied for putting, if the operation fails. */
  348. private void
  349. cos_uncopy_element_value(cos_value_t *pcv, gs_memory_t *mem, bool copy)
  350. {
  351.     if (pcv->value_type == COS_VALUE_SCALAR && copy)
  352.     gs_free_string(mem, pcv->contents.chars.data, pcv->contents.chars.size,
  353.                "cos_uncopy_element_value");
  354. }
  355.  
  356. /* ---------------- Specific object types ---------------- */
  357.  
  358. /* ------ Generic objects ------ */
  359.  
  360. private cos_proc_release(cos_generic_release);
  361. private cos_proc_write(cos_generic_write);
  362. const cos_object_procs_t cos_generic_procs = {
  363.     cos_generic_release, cos_generic_write
  364. };
  365.  
  366. cos_object_t *
  367. cos_object_alloc(gx_device_pdf *pdev, client_name_t cname)
  368. {
  369.     gs_memory_t *mem = pdev->pdf_memory;
  370.     cos_object_t *pco =
  371.     gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname);
  372.  
  373.     cos_object_init(pco, pdev, &cos_generic_procs);
  374.     return pco;
  375. }
  376.  
  377. private void
  378. cos_generic_release(cos_object_t *pco, client_name_t cname)
  379. {
  380.     /* Do nothing. */
  381. }
  382.  
  383. private int
  384. cos_generic_write(const cos_object_t *pco, gx_device_pdf *pdev)
  385. {
  386.     return_error(gs_error_Fatal);
  387. }
  388.  
  389. /* ------ Arrays ------ */
  390.  
  391. private cos_proc_release(cos_array_release);
  392. private cos_proc_write(cos_array_write);
  393. const cos_object_procs_t cos_array_procs = {
  394.     cos_array_release, cos_array_write
  395. };
  396.  
  397. cos_array_t *
  398. cos_array_alloc(gx_device_pdf *pdev, client_name_t cname)
  399. {
  400.     gs_memory_t *mem = pdev->pdf_memory;
  401.     cos_array_t *pca =
  402.     gs_alloc_struct(mem, cos_array_t, &st_cos_object, cname);
  403.  
  404.     cos_object_init((cos_object_t *)pca, pdev, &cos_array_procs);
  405.     return pca;
  406. }
  407.  
  408. cos_array_t *
  409. cos_array_from_floats(gx_device_pdf *pdev, const float *pf, uint size,
  410.               client_name_t cname)
  411. {
  412.     cos_array_t *pca = cos_array_alloc(pdev, cname);
  413.     uint i;
  414.  
  415.     if (pca == 0)
  416.     return 0;
  417.     for (i = 0; i < size; ++i) {
  418.     int code = cos_array_add_real(pca, pf[i]);
  419.  
  420.     if (code < 0) {
  421.         COS_FREE(pca, cname);
  422.         return 0;
  423.     }
  424.     }
  425.     return pca;
  426. }
  427.  
  428. private void
  429. cos_array_release(cos_object_t *pco, client_name_t cname)
  430. {
  431.     gs_memory_t *mem = cos_object_memory(pco);
  432.     cos_array_t *const pca = (cos_array_t *)pco;
  433.     cos_array_element_t *cur;
  434.     cos_array_element_t *next;
  435.  
  436.     for (cur = pca->elements; cur; cur = next) {
  437.     next = cur->next;
  438.     cos_value_free(&cur->value, pco, cname);
  439.     gs_free_object(mem, cur, cname);
  440.     }
  441.     pca->elements = 0;
  442. }
  443.  
  444. private int
  445. cos_array_write(const cos_object_t *pco, gx_device_pdf *pdev)
  446. {
  447.     stream *s = pdev->strm;
  448.     const cos_array_t *const pca = (const cos_array_t *)pco;
  449.     cos_array_element_t *first = cos_array_reorder(pca, NULL);
  450.     cos_array_element_t *pcae;
  451.     uint last_index = 0;
  452.  
  453.     pputs(s, "[");
  454.     for (pcae = first; pcae; ++last_index, pcae = pcae->next) {
  455.     for (; pcae->index > last_index; ++last_index)
  456.         pputs(s, "null\n");
  457.     cos_value_write(&pcae->value, pdev);
  458.     pputc(s, '\n');
  459.     }
  460.     DISCARD(cos_array_reorder(pca, first));
  461.     pputs(s, "]");
  462.     return 0;
  463. }
  464.  
  465. /* Put/add an element in/to an array. */
  466. int
  467. cos_array_put(cos_array_t *pca, long index, const cos_value_t *pvalue)
  468. {
  469.     gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
  470.     cos_value_t value;
  471.     int code = cos_copy_element_value(&value, mem, pvalue, true);
  472.  
  473.     if (code >= 0) {
  474.     code = cos_array_put_no_copy(pca, index, &value);
  475.     if (code < 0)
  476.         cos_uncopy_element_value(&value, mem, true);
  477.     }
  478.     return code;
  479. }
  480. int
  481. cos_array_put_no_copy(cos_array_t *pca, long index, const cos_value_t *pvalue)
  482. {
  483.     gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
  484.     cos_array_element_t **ppcae = &pca->elements;
  485.     cos_array_element_t *pcae;
  486.     cos_array_element_t *next;
  487.  
  488.     while ((next = *ppcae) != 0 && next->index > index)
  489.     ppcae = &next->next;
  490.     if (next && next->index == index) {
  491.     /* We're replacing an existing element. */
  492.     cos_value_free(&next->value, COS_OBJECT(pca),
  493.                "cos_array_put(old value)");
  494.     pcae = next;
  495.     } else {
  496.     /* Create a new element. */
  497.     pcae = gs_alloc_struct(mem, cos_array_element_t, &st_cos_array_element,
  498.                    "cos_array_put(element)");
  499.     if (pcae == 0)
  500.         return_error(gs_error_VMerror);
  501.     pcae->index = index;
  502.     pcae->next = next;
  503.     *ppcae = pcae;
  504.     }
  505.     pcae->value = *pvalue;
  506.     return 0;
  507. }
  508. private long
  509. cos_array_next_index(const cos_array_t *pca)
  510. {
  511.     return (pca->elements ? pca->elements->index + 1 : 0L);
  512. }
  513. int
  514. cos_array_add(cos_array_t *pca, const cos_value_t *pvalue)
  515. {
  516.     return cos_array_put(pca, cos_array_next_index(pca), pvalue);
  517. }
  518. int
  519. cos_array_add_no_copy(cos_array_t *pca, const cos_value_t *pvalue)
  520. {
  521.     return cos_array_put_no_copy(pca, cos_array_next_index(pca), pvalue);
  522. }
  523. int
  524. cos_array_add_c_string(cos_array_t *pca, const char *str)
  525. {
  526.     cos_value_t value;
  527.  
  528.     return cos_array_add(pca, cos_c_string_value(&value, str));
  529. }
  530. int
  531. cos_array_add_int(cos_array_t *pca, int i)
  532. {
  533.     char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
  534.     cos_value_t v;
  535.  
  536.     sprintf(str, "%d", i);
  537.     return cos_array_add(pca, cos_string_value(&v, (byte *)str, strlen(str)));
  538. }
  539. int
  540. cos_array_add_real(cos_array_t *pca, floatp r)
  541. {
  542.     byte str[50];        /****** ADHOC ******/
  543.     stream s;
  544.     cos_value_t v;
  545.  
  546.     swrite_string(&s, str, sizeof(str));
  547.     pprintg1(&s, "%g", r);
  548.     return cos_array_add(pca, cos_string_value(&v, str, stell(&s)));
  549. }
  550. int
  551. cos_array_add_object(cos_array_t *pca, cos_object_t *pco)
  552. {
  553.     cos_value_t value;
  554.  
  555.     return cos_array_add(pca, cos_object_value(&value, pco));
  556. }
  557.  
  558. /* Get the first / next element for enumerating an array. */
  559. const cos_array_element_t *
  560. cos_array_element_first(const cos_array_t *pca)
  561. {
  562.     return pca->elements;
  563. }
  564. const cos_array_element_t *
  565. cos_array_element_next(const cos_array_element_t *pca, long *pindex,
  566.                const cos_value_t **ppvalue)
  567. {
  568.     *pindex = pca->index;
  569.     *ppvalue = &pca->value;
  570.     return pca->next;
  571. }
  572.  
  573. /*
  574.  * Reorder the elements of an array for writing or after writing.  Usage:
  575.  *    first_element = cos_array_reorder(pca, NULL);
  576.  *    ...
  577.  *    cos_array_reorder(pca, first_element);
  578.  */
  579. cos_array_element_t *
  580. cos_array_reorder(const cos_array_t *pca, cos_array_element_t *first)
  581. {
  582.     cos_array_element_t *last;
  583.     cos_array_element_t *next;
  584.     cos_array_element_t *pcae;
  585.  
  586.     for (pcae = (first ? first : pca->elements), last = NULL; pcae;
  587.      pcae = next)
  588.     next = pcae->next, pcae->next = last, last = pcae;
  589.     return last;
  590. }
  591.  
  592. /* ------ Dictionaries ------ */
  593.  
  594. private cos_proc_release(cos_dict_release);
  595. private cos_proc_write(cos_dict_write);
  596. const cos_object_procs_t cos_dict_procs = {
  597.     cos_dict_release, cos_dict_write
  598. };
  599.  
  600. cos_dict_t *
  601. cos_dict_alloc(gx_device_pdf *pdev, client_name_t cname)
  602. {
  603.     gs_memory_t *mem = pdev->pdf_memory;
  604.     cos_dict_t *pcd =
  605.     gs_alloc_struct(mem, cos_dict_t, &st_cos_object, cname);
  606.  
  607.     cos_object_init((cos_object_t *)pcd, pdev, &cos_dict_procs);
  608.     return pcd;
  609. }
  610.  
  611. private void
  612. cos_dict_release(cos_object_t *pco, client_name_t cname)
  613. {
  614.     gs_memory_t *mem = cos_object_memory(pco);
  615.     cos_dict_t *const pcd = (cos_dict_t *)pco;
  616.     cos_dict_element_t *cur;
  617.     cos_dict_element_t *next;
  618.  
  619.     for (cur = pcd->elements; cur; cur = next) {
  620.     next = cur->next;
  621.     cos_value_free(&cur->value, pco, cname);
  622.     if (cur->owns_key)
  623.         gs_free_string(mem, cur->key.data, cur->key.size, cname);
  624.     gs_free_object(mem, cur, cname);
  625.     }
  626.     pcd->elements = 0;
  627. }
  628.  
  629. /* Write the elements of a dictionary. */
  630. private int
  631. cos_elements_write(stream *s, const cos_dict_element_t *pcde,
  632.            gx_device_pdf *pdev)
  633. {
  634.     /* Temporarily replace the output stream in pdev. */
  635.     stream *save = pdev->strm;
  636.  
  637.     pdev->strm = s;
  638.     for (; pcde; pcde = pcde->next) {
  639.     pdf_write_value(pdev, pcde->key.data, pcde->key.size);
  640.     pputc(s, ' ');
  641.     cos_value_write(&pcde->value, pdev);
  642.     pputc(s, '\n');
  643.     }
  644.     pdev->strm = save;
  645.     return 0;
  646. }
  647. int
  648. cos_dict_elements_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
  649. {
  650.     return cos_elements_write(pdev->strm, pcd->elements, pdev);
  651. }
  652.  
  653. private int
  654. cos_dict_write(const cos_object_t *pco, gx_device_pdf *pdev)
  655. {
  656.     stream *s = pdev->strm;
  657.  
  658.     pputs(s, "<<");
  659.     cos_dict_elements_write((const cos_dict_t *)pco, pdev);
  660.     pputs(s, ">>");
  661.     return 0;
  662. }
  663.  
  664. /* Write/delete definitions of named objects. */
  665. /* This is a special-purpose facility for pdf_close. */
  666. int
  667. cos_dict_objects_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
  668. {
  669.     const cos_dict_element_t *pcde = pcd->elements;
  670.  
  671.     for (; pcde; pcde = pcde->next)
  672.     if (COS_VALUE_IS_OBJECT(&pcde->value) &&
  673.         pcde->value.contents.object->id)
  674.         cos_write_object(pcde->value.contents.object, pdev);
  675.     return 0;
  676. }
  677. int
  678. cos_dict_objects_delete(cos_dict_t *pcd)
  679. {
  680.     cos_dict_element_t *pcde = pcd->elements;
  681.  
  682.     /*
  683.      * Delete the objects' IDs so that freeing the dictionary will
  684.      * free them.
  685.      */
  686.     for (; pcde; pcde = pcde->next)
  687.     pcde->value.contents.object->id = 0;
  688.     return 0;
  689. }
  690.  
  691. /* Put an element in a dictionary. */
  692. #define DICT_COPY_KEY 1
  693. #define DICT_COPY_VALUE 2
  694. #define DICT_FREE_KEY 4
  695. #define DICT_COPY_ALL (DICT_COPY_KEY | DICT_COPY_VALUE | DICT_FREE_KEY)
  696. private int
  697. cos_dict_put_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
  698.           const cos_value_t *pvalue, int flags)
  699. {
  700.     gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
  701.     cos_dict_element_t **ppcde = &pcd->elements;
  702.     cos_dict_element_t *pcde;
  703.     cos_dict_element_t *next;
  704.     cos_value_t value;
  705.     int code;
  706.  
  707.     while ((next = *ppcde) != 0 &&
  708.        bytes_compare(next->key.data, next->key.size, key_data, key_size)
  709.        )
  710.     ppcde = &next->next;
  711.     if (next) {
  712.     /* We're replacing an existing element. */
  713.     code = cos_copy_element_value(&value, mem, pvalue,
  714.                       (flags & DICT_COPY_VALUE) != 0);
  715.     if (code < 0)
  716.         return code;
  717.     if (flags & DICT_FREE_KEY)
  718.         gs_free_const_string(mem, key_data, key_size,
  719.                  "cos_dict_put(new key)");
  720.     cos_value_free(&next->value, COS_OBJECT(pcd),
  721.                "cos_dict_put(old value)");
  722.     pcde = next;
  723.     } else {
  724.     /* Create a new element. */
  725.     byte *copied_key_data;
  726.  
  727.     if (flags & DICT_COPY_KEY) {
  728.         copied_key_data = gs_alloc_string(mem, key_size,
  729.                           "cos_dict_put(key)");
  730.         if (copied_key_data == 0)
  731.         return_error(gs_error_VMerror);
  732.         memcpy(copied_key_data, key_data, key_size);
  733.     } else
  734.         copied_key_data = (byte *)key_data;    /* OK to break const */
  735.     pcde = gs_alloc_struct(mem, cos_dict_element_t, &st_cos_dict_element,
  736.                    "cos_dict_put(element)");
  737.     code = cos_copy_element_value(&value, mem, pvalue,
  738.                       (flags & DICT_COPY_VALUE) != 0);
  739.     if (pcde == 0 || code < 0) {
  740.         if (code >= 0)
  741.         cos_uncopy_element_value(&value, mem,
  742.                      (flags & DICT_COPY_VALUE) != 0);
  743.         gs_free_object(mem, pcde, "cos_dict_put(element)");
  744.         if (flags & DICT_COPY_KEY)
  745.         gs_free_string(mem, copied_key_data, key_size,
  746.                    "cos_dict_put(key)");
  747.         return (code < 0 ? code : gs_note_error(gs_error_VMerror));
  748.     }
  749.     pcde->key.data = copied_key_data;
  750.     pcde->key.size = key_size;
  751.     pcde->owns_key = (flags & DICT_FREE_KEY) != 0;
  752.     pcde->next = next;
  753.     *ppcde = pcde;
  754.     }
  755.     pcde->value = value;
  756.     return 0;
  757. }
  758. int
  759. cos_dict_put(cos_dict_t *pcd, const byte *key_data, uint key_size,
  760.          const cos_value_t *pvalue)
  761. {
  762.     return cos_dict_put_copy(pcd, key_data, key_size, pvalue, DICT_COPY_ALL);
  763. }
  764. int
  765. cos_dict_put_no_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
  766.              const cos_value_t *pvalue)
  767. {
  768.     return cos_dict_put_copy(pcd, key_data, key_size, pvalue,
  769.                  DICT_COPY_KEY | DICT_FREE_KEY);
  770. }
  771. int
  772. cos_dict_put_c_key(cos_dict_t *pcd, const char *key, const cos_value_t *pvalue)
  773. {
  774.     return cos_dict_put_copy(pcd, (const byte *)key, strlen(key), pvalue,
  775.                  DICT_COPY_VALUE);
  776. }
  777. int
  778. cos_dict_put_c_key_string(cos_dict_t *pcd, const char *key,
  779.               const byte *data, uint size)
  780. {
  781.     cos_value_t value;
  782.  
  783.     cos_string_value(&value, data, size);
  784.     return cos_dict_put_c_key(pcd, key, &value);
  785. }
  786. int
  787. cos_dict_put_c_key_int(cos_dict_t *pcd, const char *key, int value)
  788. {
  789.     char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
  790.  
  791.     sprintf(str, "%d", value);
  792.     return cos_dict_put_c_key_string(pcd, key, (byte *)str, strlen(str));
  793. }
  794. int
  795. cos_dict_put_c_key_real(cos_dict_t *pcd, const char *key, floatp value)
  796. {
  797.     byte str[50];        /****** ADHOC ******/
  798.     stream s;
  799.  
  800.     swrite_string(&s, str, sizeof(str));
  801.     pprintg1(&s, "%g", value);
  802.     return cos_dict_put_c_key_string(pcd, key, str, stell(&s));
  803. }
  804. int
  805. cos_dict_put_c_key_floats(cos_dict_t *pcd, const char *key, const float *pf,
  806.               uint size)
  807. {
  808.     cos_array_t *pca = cos_array_from_floats(pcd->pdev, pf, size,
  809.                          "cos_dict_put_c_key_floats");
  810.     int code;
  811.  
  812.     if (pca == 0)
  813.     return_error(gs_error_VMerror);
  814.     code = cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
  815.     if (code < 0)
  816.     COS_FREE(pca, "cos_dict_put_c_key_floats");
  817.     return code;
  818. }
  819. int
  820. cos_dict_put_c_key_object(cos_dict_t *pcd, const char *key, cos_object_t *pco)
  821. {
  822.     cos_value_t value;
  823.  
  824.     return cos_dict_put_c_key(pcd, key, cos_object_value(&value, pco));
  825. }
  826. int
  827. cos_dict_put_string(cos_dict_t *pcd, const byte *key_data, uint key_size,
  828.             const byte *value_data, uint value_size)
  829. {
  830.     cos_value_t cvalue;
  831.  
  832.     return cos_dict_put(pcd, key_data, key_size,
  833.             cos_string_value(&cvalue, value_data, value_size));
  834. }
  835. int
  836. cos_dict_put_c_strings(cos_dict_t *pcd, const char *key, const char *value)
  837. {
  838.     cos_value_t cvalue;
  839.  
  840.     return cos_dict_put_c_key(pcd, key, cos_c_string_value(&cvalue, value));
  841. }
  842.  
  843. /* Look up a key in a dictionary. */
  844. const cos_value_t *
  845. cos_dict_find(const cos_dict_t *pcd, const byte *key_data, uint key_size)
  846. {
  847.     cos_dict_element_t *pcde = pcd->elements;
  848.  
  849.     for (; pcde; pcde = pcde->next)
  850.     if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size))
  851.         return &pcde->value;
  852.     return 0;
  853. }
  854. const cos_value_t *
  855. cos_dict_find_c_key(const cos_dict_t *pcd, const char *key)
  856. {
  857.     return cos_dict_find(pcd, (const byte *)key, strlen(key));
  858. }
  859.  
  860. /* Set up a parameter list that writes into a Cos dictionary. */
  861.  
  862. /* We'll implement the other printers later if we have to. */
  863. private param_proc_xmit_typed(cos_param_put_typed);
  864. private const gs_param_list_procs cos_param_list_writer_procs = {
  865.     cos_param_put_typed,
  866.     NULL /* begin_collection */ ,
  867.     NULL /* end_collection */ ,
  868.     NULL /* get_next_key */ ,
  869.     gs_param_request_default,
  870.     gs_param_requested_default
  871. };
  872. private int
  873. cos_param_put_typed(gs_param_list * plist, gs_param_name pkey,
  874.             gs_param_typed_value * pvalue)
  875. {
  876.     cos_param_list_writer_t *const pclist =
  877.     (cos_param_list_writer_t *)plist;
  878.     gx_device_pdf *pdev = pclist->pcd->pdev;
  879.     gs_memory_t *mem = pclist->memory;
  880.     cos_value_t value;
  881.     cos_array_t *pca;
  882.     int key_len = strlen(pkey);
  883.     byte key_chars[100];        /****** ADHOC ******/
  884.     int code;
  885.  
  886.     if (key_len > sizeof(key_chars) - 1)
  887.     return_error(gs_error_limitcheck);
  888.     switch (pvalue->type) {
  889.     default: {
  890.     param_printer_params_t ppp;
  891.     printer_param_list_t pplist;
  892.     stream s;
  893.     int len, skip;
  894.     byte *str;
  895.  
  896.     ppp = param_printer_params_default;
  897.     ppp.prefix = ppp.suffix = ppp.item_prefix = ppp.item_suffix = 0;
  898.     ppp.print_ok = pclist->print_ok;
  899.     s_init_param_printer(&pplist, &ppp, &s);
  900.     swrite_position_only(&s);
  901.     param_write_typed((gs_param_list *)&pplist, "", pvalue);
  902.     len = stell(&s);
  903.     str = gs_alloc_string(mem, len, "cos_param_put(string)");
  904.     if (str == 0)
  905.         return_error(gs_error_VMerror);
  906.     swrite_string(&s, str, len);
  907.     param_write_typed((gs_param_list *)&pplist, "", pvalue);
  908.     /*
  909.      * The string starts with an initial / or /<space>, which
  910.      * we need to remove.
  911.      */
  912.     skip = (str[1] == ' ' ? 2 : 1);
  913.     memmove(str, str + skip, len - skip);
  914.     str = gs_resize_string(mem, str, len, len - skip,
  915.                    "cos_param_put(string)");
  916.     cos_string_value(&value, str, len - skip);
  917.     }
  918.     break;
  919.     case gs_param_type_int_array: {
  920.     uint i;
  921.  
  922.     pca = cos_array_alloc(pdev, "cos_param_put(array)");
  923.     if (pca == 0)
  924.         return_error(gs_error_VMerror);
  925.     for (i = 0; i < pvalue->value.ia.size; ++i)
  926.         CHECK(cos_array_add_int(pca, pvalue->value.ia.data[i]));
  927.     }
  928.     av:
  929.     cos_object_value(&value, COS_OBJECT(pca));
  930.     break;
  931.     case gs_param_type_float_array: {
  932.     uint i;
  933.  
  934.     pca = cos_array_alloc(pdev, "cos_param_put(array)");
  935.     if (pca == 0)
  936.         return_error(gs_error_VMerror);
  937.     for (i = 0; i < pvalue->value.ia.size; ++i)
  938.         CHECK(cos_array_add_real(pca, pvalue->value.fa.data[i]));
  939.     }
  940.     goto av;
  941.     case gs_param_type_string_array:
  942.     case gs_param_type_name_array:
  943.     /****** NYI ******/
  944.     return_error(gs_error_typecheck);
  945.     }
  946.     memcpy(key_chars + 1, pkey, key_len);
  947.     key_chars[0] = '/';
  948.     return cos_dict_put_no_copy(pclist->pcd, key_chars, key_len + 1, &value);
  949. }
  950.  
  951. int
  952. cos_param_list_writer_init(cos_param_list_writer_t *pclist, cos_dict_t *pcd,
  953.                int print_ok)
  954. {
  955.     gs_param_list_init((gs_param_list *)pclist, &cos_param_list_writer_procs,
  956.                COS_OBJECT_MEMORY(pcd));
  957.     pclist->pcd = pcd;
  958.     pclist->print_ok = print_ok;
  959.     return 0;
  960. }
  961.  
  962. /* ------ Streams ------ */
  963.  
  964. private cos_proc_release(cos_stream_release);
  965. private cos_proc_write(cos_stream_write);
  966. const cos_object_procs_t cos_stream_procs = {
  967.     cos_stream_release, cos_stream_write
  968. };
  969.  
  970. cos_stream_t *
  971. cos_stream_alloc(gx_device_pdf *pdev, client_name_t cname)
  972. {
  973.     gs_memory_t *mem = pdev->pdf_memory;
  974.     cos_stream_t *pcs =
  975.     gs_alloc_struct(mem, cos_stream_t, &st_cos_object, cname);
  976.  
  977.     cos_object_init((cos_object_t *)pcs, pdev, &cos_stream_procs);
  978.     return pcs;
  979. }
  980.  
  981. private void
  982. cos_stream_release(cos_object_t *pco, client_name_t cname)
  983. {
  984.     gs_memory_t *mem = cos_object_memory(pco);
  985.     cos_stream_t *const pcs = (cos_stream_t *)pco;
  986.     cos_stream_piece_t *cur;
  987.     cos_stream_piece_t *next;
  988.  
  989.     for (cur = pcs->pieces; cur; cur = next) {
  990.     next = cur->next;
  991.     gs_free_object(mem, cur, cname);
  992.     }
  993.     pcs->pieces = 0;
  994.     cos_dict_release(pco, cname);
  995. }
  996.  
  997. /* Find the total length of a stream. */
  998. private long
  999. cos_stream_length(const cos_stream_t *pcs)
  1000. {
  1001.     const cos_stream_piece_t *pcsp = pcs->pieces;
  1002.     long length;
  1003.  
  1004.     for (length = 0; pcsp; pcsp = pcsp->next)
  1005.     length += pcsp->size;
  1006.     return length;
  1007. }
  1008.  
  1009. /* Write the (dictionary) elements of a stream. */
  1010. /* (This procedure is exported.) */
  1011. int
  1012. cos_stream_elements_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
  1013. {
  1014.     return cos_elements_write(pdev->strm, pcs->elements, pdev);
  1015. }
  1016.  
  1017. /* Write the contents of a stream.  (This procedure is exported.) */
  1018. int
  1019. cos_stream_contents_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
  1020. {
  1021.     stream *s = pdev->strm;
  1022.     cos_stream_piece_t *pcsp;
  1023.     cos_stream_piece_t *last;
  1024.     cos_stream_piece_t *next;
  1025.     FILE *sfile = pdev->streams.file;
  1026.     long end_pos;
  1027.     int code;
  1028.  
  1029.     sflush(pdev->streams.strm);
  1030.     end_pos = ftell(sfile);
  1031.  
  1032.     /* Reverse the elements temporarily. */
  1033.     for (pcsp = pcs->pieces, last = NULL; pcsp; pcsp = next)
  1034.     next = pcsp->next, pcsp->next = last, last = pcsp;
  1035.     for (pcsp = last, code = 0; pcsp && code >= 0; pcsp = pcsp->next) {
  1036.     fseek(sfile, pcsp->position, SEEK_SET);
  1037.     pdf_copy_data(s, sfile, pcsp->size);
  1038.     }
  1039.     /* Reverse the elements back. */
  1040.     for (pcsp = last, last = NULL; pcsp; pcsp = next)
  1041.     next = pcsp->next, pcsp->next = last, last = pcsp;
  1042.  
  1043.     fseek(sfile, end_pos, SEEK_SET);
  1044.     return code;
  1045. }
  1046.  
  1047. private int
  1048. cos_stream_write(const cos_object_t *pco, gx_device_pdf *pdev)
  1049. {
  1050.     stream *s = pdev->strm;
  1051.     const cos_stream_t *const pcs = (const cos_stream_t *)pco;
  1052.     int code;
  1053.  
  1054.     pputs(s, "<<");
  1055.     cos_elements_write(s, pcs->elements, pdev);
  1056.     pprintld1(s, "/Length %ld>>stream\n", cos_stream_length(pcs));
  1057.     code = cos_stream_contents_write(pcs, pdev);
  1058.     pputs(s, "\nendstream\n");
  1059.  
  1060.     return code;
  1061. }
  1062.  
  1063. /* Return a stream's dictionary (just a cast). */
  1064. cos_dict_t *
  1065. cos_stream_dict(cos_stream_t *pcs)
  1066. {
  1067.     return (cos_dict_t *)pcs;
  1068. }
  1069.  
  1070. /* Add a contents piece to a stream object: size bytes just written on */
  1071. /* streams.strm. */
  1072. int
  1073. cos_stream_add(cos_stream_t *pcs, uint size)
  1074. {
  1075.     gx_device_pdf *pdev = pcs->pdev;
  1076.     stream *s = pdev->streams.strm;
  1077.     long position = stell(s);
  1078.     cos_stream_piece_t *prev = pcs->pieces;
  1079.  
  1080.     /* Check for consecutive writing -- just an optimization. */
  1081.     if (prev != 0 && prev->position + prev->size + size == position) {
  1082.     prev->size += size;
  1083.     } else {
  1084.     gs_memory_t *mem = pdev->pdf_memory;
  1085.     cos_stream_piece_t *pcsp =
  1086.         gs_alloc_struct(mem, cos_stream_piece_t, &st_cos_stream_piece,
  1087.                 "cos_stream_add");
  1088.  
  1089.     if (pcsp == 0)
  1090.         return_error(gs_error_VMerror);
  1091.     pcsp->position = position - size;
  1092.     pcsp->size = size;
  1093.     pcsp->next = pcs->pieces;
  1094.     pcs->pieces = pcsp;
  1095.     }
  1096.     return 0;
  1097. }
  1098. int
  1099. cos_stream_add_since(cos_stream_t *pcs, long start_pos)
  1100. {
  1101.     return cos_stream_add(pcs,
  1102.               (uint)(stell(pcs->pdev->streams.strm) - start_pos));
  1103. }
  1104.  
  1105. /* Add bytes to a stream object. */
  1106. int
  1107. cos_stream_add_bytes(cos_stream_t *pcs, const byte *data, uint size)
  1108. {
  1109.     pwrite(pcs->pdev->streams.strm, data, size);
  1110.     return cos_stream_add(pcs, size);
  1111. }
  1112.  
  1113. /* Create a stream that writes into a Cos stream. */
  1114. /* Closing the stream will free it. */
  1115. /* Note that this is not a filter. */
  1116. typedef struct cos_write_stream_state_s {
  1117.     stream_state_common;
  1118.     cos_stream_t *pcs;
  1119.     gx_device_pdf *pdev;
  1120.     stream *s;            /* pointer back to stream */
  1121.     stream *target;        /* use this instead of strm */
  1122. } cos_write_stream_state_t;
  1123. gs_private_st_suffix_add4(st_cos_write_stream_state, cos_write_stream_state_t,
  1124.               "cos_write_stream_state_t",
  1125.               cos_ws_state_enum_ptrs, cos_ws_state_reloc_ptrs,
  1126.               st_stream_state, pcs, pdev, s, target);
  1127. private int
  1128. cos_write_stream_process(stream_state * st, stream_cursor_read * pr,
  1129.              stream_cursor_write * ignore_pw, bool last)
  1130. {
  1131.     uint count = pr->limit - pr->ptr;
  1132.     cos_write_stream_state_t *ss = (cos_write_stream_state_t *)st;
  1133.     gx_device_pdf *pdev = ss->pdev;
  1134.     stream *target = ss->target;
  1135.     long start_pos = stell(pdev->streams.strm);
  1136.     int code;
  1137.  
  1138.     pwrite(target, pr->ptr + 1, count);
  1139.     pr->ptr = pr->limit;
  1140.     sflush(target);
  1141.     code = cos_stream_add_since(ss->pcs, start_pos);
  1142.     return (code < 0 ? ERRC : 0);
  1143. }
  1144. private int
  1145. cos_write_stream_close(stream *s)
  1146. {
  1147.     cos_write_stream_state_t *ss = (cos_write_stream_state_t *)s->state;
  1148.     int status;
  1149.  
  1150.     sflush(s);
  1151.     status = s_close_filters(&ss->target, ss->pdev->streams.strm);
  1152.     return (status < 0 ? status : s_std_close(s));
  1153. }
  1154.  
  1155. private const stream_procs cos_s_procs = {
  1156.     s_std_noavailable, s_std_noseek, s_std_write_reset,
  1157.     s_std_write_flush, cos_write_stream_close, cos_write_stream_process
  1158. };
  1159. private const stream_template cos_write_stream_template = {
  1160.     &st_cos_write_stream_state, 0, cos_write_stream_process, 1, 1
  1161. };
  1162. stream *
  1163. cos_write_stream_alloc(cos_stream_t *pcs, gx_device_pdf *pdev,
  1164.                client_name_t cname)
  1165. {
  1166.     gs_memory_t *mem = pdev->pdf_memory;
  1167.     stream *s = s_alloc(mem, cname);
  1168.     cos_write_stream_state_t *ss = (cos_write_stream_state_t *)
  1169.     s_alloc_state(mem, &st_cos_write_stream_state, cname);
  1170. #define CWS_BUF_SIZE 512    /* arbitrary */
  1171.     byte *buf = gs_alloc_bytes(mem, CWS_BUF_SIZE, cname);
  1172.  
  1173.     if (s == 0 || ss == 0 || buf == 0)
  1174.     goto fail;
  1175.     ss->template = &cos_write_stream_template;
  1176.     ss->pcs = pcs;
  1177.     ss->pdev = pdev;
  1178.     ss->s = s;
  1179.     ss->target = pdev->streams.strm; /* not s->strm */
  1180.     s_std_init(s, buf, CWS_BUF_SIZE, &cos_s_procs, s_mode_write);
  1181.     s->state = (stream_state *)ss;
  1182.     return s;
  1183. #undef CWS_BUF_SIZE
  1184.  fail:
  1185.     gs_free_object(mem, buf, cname);
  1186.     gs_free_object(mem, ss, cname);
  1187.     gs_free_object(mem, s, cname);
  1188.     return 0;
  1189. }
  1190.